package com.ipay.utils;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;

public class HttpClientUtils {

	private static Set<Header> DEFAULT_HEADERS = new HashSet<>();
	private static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
	static {
		DEFAULT_HEADERS.add(new BasicHeader("User-Agent",
				"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));
		DEFAULT_HEADERS.add(new BasicHeader("Accept",
				"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"));
		DEFAULT_HEADERS.add(new BasicHeader("Accept-Encoding", "gzip,deflate,sdch"));
		DEFAULT_HEADERS.add(new BasicHeader("Content-Type", "application/json;utf-8"));
	}

	static class HttpClientHolder {
		static CloseableHttpClient httpClient = create();
	}

	public static CloseableHttpClient getDefaultInstance() {
		return HttpClientHolder.httpClient;
	}

	public static CloseableHttpClient create() {
		return create(false);
	}

	public static CloseableHttpClient create(boolean single) {
		return create(single, 10000);
	}

	@SuppressWarnings("resource")
	public static CloseableHttpClient create(boolean single, int connectTimeout) {
		HttpClientConnectionManager connManager;
		if (single)
			connManager = new BasicHttpClientConnectionManager();
		else {
			PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(60, TimeUnit.SECONDS);
			cm.setDefaultMaxPerRoute(1000);
			cm.setMaxTotal(1000);
			connManager = cm;
		}
		RequestConfig requestConfig = RequestConfig.custom().setCircularRedirectsAllowed(true)
				.setConnectTimeout(connectTimeout).setExpectContinueEnabled(true).build();
		CloseableHttpClient httpclient = HttpClientBuilder.create().setConnectionManager(connManager)
				.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()).setDefaultRequestConfig(requestConfig)
				.disableAuthCaching().disableAutomaticRetries().disableConnectionState().disableCookieManagement()
				.setDefaultHeaders(DEFAULT_HEADERS).build();
		return httpclient;
	}

	public static String getResponseText(String url) throws IOException {
		return getResponseText(url, null, "UTF-8");
	}

	public static String getResponseText(String url, Map<String, String> params) throws IOException {
		return getResponseText(url, params, "UTF-8");
	}

	public static String getResponseText(String url, Map<String, String> params, Map<String, String> headers)
			throws IOException {
		return getResponseText(url, params, headers, "UTF-8");
	}

	public static String getResponseText(String url, Map<String, String> params, String charset) throws IOException {
		return getResponseText(url, params, null, charset);
	}

	public static String getResponseText(String url, Map<String, String> params, Map<String, String> headers,
			String charset) throws IOException {
		HttpGet httpRequest = null;
		StringBuilder sb = new StringBuilder(url);
		if (params != null && params.size() > 0) {
			sb.append(url.indexOf('?') < 0 ? '?' : '&');
			for (Map.Entry<String, String> entry : params.entrySet()) {
				sb.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), charset)).append("&");
			}
			sb.deleteCharAt(sb.length() - 1);
		}
		httpRequest = new HttpGet(sb.toString());
		if (headers != null && headers.size() > 0)
			for (Map.Entry<String, String> entry : headers.entrySet())
				httpRequest.addHeader(entry.getKey(), entry.getValue());
		try {
			return getDefaultInstance().execute(httpRequest, new BasicResponseHandler(charset));
		} finally {
			httpRequest.releaseConnection();
		}
	}
	
	public static void send() {
		
	}

	public static String postResponseText(String url, Map<String, String> params) throws IOException {
		return postResponseText(url, params, "UTF-8");
	}

	public static String postResponseText(String url, Map<String, String> params, Map<String, String> headers)
			throws IOException {
		return postResponseText(url, params, headers, "UTF-8");
	}

	public static String postResponseText(String url, Map<String, String> params, String charset) throws IOException {
		return postResponseText(url, params, null, charset);
	}

	public static String postResponseText(String url, Map<String, String> params, Map<String, String> headers,
			String charset) throws IOException {
		HttpPost httpRequest = new HttpPost(url);
		if (params != null && params.size() > 0) {
			List<NameValuePair> nvps = new ArrayList<>();
			for (Map.Entry<String, String> entry : params.entrySet())
				nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
			httpRequest.setEntity(new UrlEncodedFormEntity(nvps, charset));
		}
		if (headers != null && headers.size() > 0)
			for (Map.Entry<String, String> entry : headers.entrySet())
				httpRequest.addHeader(entry.getKey(), entry.getValue());
		try {
			return getDefaultInstance().execute(httpRequest, new BasicResponseHandler(charset));
		} finally {
			httpRequest.releaseConnection();
		}
	}

	public static String postResponseText(String url, String body, Map<String, String> headers, String charset)
			throws IOException {
		HttpPost httpRequest = new HttpPost(url);
		httpRequest.setEntity(new StringEntity(body, charset));
		if (headers != null && headers.size() > 0)
			for (Map.Entry<String, String> entry : headers.entrySet())
				httpRequest.addHeader(entry.getKey(), entry.getValue());
		try {
			return getDefaultInstance().execute(httpRequest, new BasicResponseHandler(charset));
		} finally {
			httpRequest.releaseConnection();
		}
	}

	public static String post(String url, String entity) throws IOException {
		return invoke("POST", url, entity);
	}

	public static String post(String url, String entity, String charset) throws IOException {
		return invoke("POST", url, entity, charset);
	}

	public static String put(String url, String entity) throws IOException {
		return invoke("PUT", url, entity);
	}

	public static String put(String url, String entity, String charset) throws IOException {
		return invoke("PUT", url, entity, charset);
	}

	public static String delete(String url) throws IOException {
		return invoke("DELETE", url, null);
	}

	public static String get(String url) throws IOException {
		return invoke("GET", url, null);
	}

	private static String invoke(String method, String url, String entity) throws IOException {
		return invoke(method, url, entity, "UTF-8");
	}

	private static String invoke(String method, String url, String entity, String charset) throws IOException {
		HttpRequestBase httpRequest = null;
		if (method.equalsIgnoreCase("GET"))
			httpRequest = new HttpGet(url);
		else if (method.equalsIgnoreCase("POST"))
			httpRequest = new HttpPost(url);
		else if (method.equalsIgnoreCase("PUT"))
			httpRequest = new HttpPut(url);
		else if (method.equalsIgnoreCase("DELETE"))
			httpRequest = new HttpDelete(url);
		if (entity != null)
			((HttpEntityEnclosingRequestBase) httpRequest).setEntity(new StringEntity(entity, charset));
		try {
			return getDefaultInstance().execute(httpRequest, new BasicResponseHandler(charset));
		} finally {
			if (httpRequest != null)
				httpRequest.releaseConnection();
		}
	}

	static class BasicResponseHandler implements ResponseHandler<String> {

		private String charset;

		public String getCharset() {
			return charset;
		}

		public void setCharset(String charset) {
			this.charset = charset;
		}

		BasicResponseHandler(String charset) {
			this.charset = charset;
		}

		@Override
		public String handleResponse(final HttpResponse response) throws HttpResponseException, IOException {
			final StatusLine statusLine = response.getStatusLine();
			final HttpEntity entity = response.getEntity();
			if (statusLine.getStatusCode() >= 300) {
				EntityUtils.consume(entity);
				throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
			}
			return entity == null ? null : EntityUtils.toString(entity, charset);
		}

	}

	/**
	 * post请求传输String参数 
	 * 例如：name=Jack&sex=1&type=2
	 * 
	 * @param url
	 *            url地址
	 * @param strParam
	 *            参数
	 * @return
	 */
	public static JSONObject httpPost(String url, String strParam) {
		// post请求返回结果
		CloseableHttpClient httpClient = HttpClients.createDefault();
		JSONObject jsonResult = null;
		HttpPost httpPost = new HttpPost(url);
		// 设置请求和传输超时时间
		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();
		httpPost.setConfig(requestConfig);
		try {
			if (null != strParam) {
				// 解决中文乱码问题
				StringEntity entity = new StringEntity(strParam, "utf-8");
				entity.setContentEncoding("UTF-8");
				entity.setContentType("application/x-www-form-urlencoded");
				httpPost.setEntity(entity);
			}
			CloseableHttpResponse result = httpClient.execute(httpPost);
			// 请求发送成功，并得到响应
			if (result.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				String str = "";
				try {
					// 读取服务器返回过来的json字符串数据
					str = EntityUtils.toString(result.getEntity(), "utf-8");
					// 把json字符串转换成json对象
					jsonResult = JSONObject.parseObject(str);
				} catch (Exception e) {
					logger.error("post请求提交失败:" + url, e);
				}
			}
		} catch (IOException e) {
			logger.error("post请求提交失败:" + url, e);
		} finally {
			httpPost.releaseConnection();
		}
		return jsonResult;
	}

}
